package com.stellar.web.core.aspect;

import com.stellar.core.context.LoginContextHolder;

import com.stellar.web.core.exception.PermissionException;
import com.stellar.web.core.validator.ValidatorRole;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * 权限校验切面，用于拦截带有{@link ValidatorRole}注解的方法进行角色权限校验
 *
 * @Author: Jqchan_
 * @Description: 通过AOP实现动态角色权限校验，确保仅允许具有指定角色的用户访问资源
 */

@Slf4j
@Aspect
@Component
public class ValidatorRoleAspect {

    private static final String ACCOUNT_PERMISSION_ERROR = "帐号身份异常";

    private static final String ACCOUNT_PERMISSION_DEFINED = "帐号权限不足";


    /**
     * 权限校验切面方法，环绕通知
     *
     * @param joinPoint     切入点，提供被拦截方法的信息
     * @param validatorRole 注解实例，包含所需的角色列表
     * @return 被拦截方法的执行结果
     * @throws Throwable 如果权限校验失败或方法执行出错
     */
    @Around("@annotation(validatorRole)")
    public Object validatorRole(ProceedingJoinPoint joinPoint, ValidatorRole validatorRole) throws Throwable {
        // 从注解中获取需要的角色
        String[] requiredRole = validatorRole.value();
        // 执行动态权限校验
        this.validatorUserRole(requiredRole);
        // 执行目标方法
        return joinPoint.proceed();
    }

    /**
     * 校验当前用户是否具备至少一个指定的角色
     *
     * @param requiredRoles 需要的角色数组，若为空数组则表示只需登录无需特定角色
     * @throws PermissionException 若用户未登录或角色校验失败
     */
    private void validatorUserRole(String[] requiredRoles) {
        // 获取当前用户角色信息（多个角色用逗号分隔）
        String currentRoleStr = LoginContextHolder.getRole();

        // 校验用户是否登录
        if (StringUtils.isBlank(currentRoleStr)) {
            log.error("ValidatorRoleAspect.validatorUserRole.error.帐号身份异常:{}", ACCOUNT_PERMISSION_ERROR);
            throw new PermissionException(ACCOUNT_PERMISSION_ERROR);
        }

        // 处理空角色配置（允许登录用户访问）
        if (requiredRoles == null || requiredRoles.length == 0) {
            return; // 无需特定角色，登录即可访问
        }

        // 转换角色集合（自动去重）
        Set<String> requiredRoleSet = Arrays.stream(requiredRoles)
                .collect(Collectors.toSet());

        // 解析当前用户角色（去空格并转换为集合）
        Set<String> currentRoles = Arrays.stream(currentRoleStr.split(","))
                .map(String::trim)
                .collect(Collectors.toSet());

        // 检查角色交集
        boolean hasValidRole = currentRoles.stream()
                .anyMatch(requiredRoleSet::contains);

        // 无有效角色时抛出异常
        if (!hasValidRole) {
            log.error("ValidatorRoleAspect.validatorUserRole.error.帐号权限不足:{}", ACCOUNT_PERMISSION_DEFINED);
            throw new PermissionException(ACCOUNT_PERMISSION_DEFINED);
        }
    }

}